package com.jcodecraeer.xrecyclerview.progressindicator;

import com.jcodecraeer.xrecyclerview.progressindicator.indicator.*;
import com.jcodecraeer.xrecyclerview.utils.AttrUtils;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.app.Context;

public class AVLoadingIndicatorView extends Component implements Component.DrawTask,
        Component.BindStateChangedListener {
    //indicators
    public static final int SysProgress=-1;
    public static final int BallPulse=0;
    public static final int BallGridPulse=1;
    public static final int BallClipRotate=2;
    public static final int BallClipRotatePulse=3;
    public static final int SquareSpin=4;
    public static final int BallClipRotateMultiple=5;
    public static final int BallPulseRise=6;
    public static final int BallRotate=7;
    public static final int CubeTransition=8;
    public static final int BallZigZag=9;
    public static final int BallZigZagDeflect=10;
    public static final int BallTrianglePath=11;
    public static final int BallScale=12;
    public static final int LineScale=13;
    public static final int LineScaleParty=14;
    public static final int BallScaleMultiple=15;
    public static final int BallPulseSync=16;
    public static final int BallBeat=17;
    public static final int LineScalePulseOut=18;
    public static final int LineScalePulseOutRapid=19;
    public static final int BallScaleRipple=20;
    public static final int BallScaleRippleMultiple=21;
    public static final int BallSpinFadeLoader=22;
    public static final int LineSpinFadeLoader=23;
    public static final int TriangleSkewSpin=24;
    public static final int Pacman=25;
    public static final int BallGridBeat=26;
    public static final int SemiCircleSpin=27;

    //Sizes (with defaults in DP)
    public static final int DEFAULT_SIZE=30;

    //attrs
    private int mIndicatorId;
    private int mIndicatorColor;
    private boolean mHasAnimation = false;

    private Paint mPaint;
    private BaseIndicatorController mIndicatorController;


    public AVLoadingIndicatorView(Context context) {
        super(context);
        init(context, null, null);
    }

    public AVLoadingIndicatorView(Context context, AttrSet attrSet) {
        super(context, attrSet);
        init(context, attrSet, null);

    }

    public AVLoadingIndicatorView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init(context, attrSet, styleName);
    }

    private void init(Context context, AttrSet attrSet, String styleName){
        mIndicatorId = AttrUtils.getIntFromAttr(attrSet, "avl_indicator_int", BallGridPulse);
        mIndicatorColor = AttrUtils.getColorFromAttr(attrSet, "avl_indicator_color", Color.WHITE.getValue());
        mPaint=new Paint();

        mPaint.setColor(new Color(mIndicatorColor));
        mPaint.setStyle(Paint.Style.FILL_STYLE);
        mPaint.setAntiAlias(true);
        if (!mHasAnimation){
            mHasAnimation=true;
            applyAnimation();
        }
        applyIndicator();
        setEstimateSizeListener(new EstimateSizeListener() {
            @Override
            public boolean onEstimateSize(int widthEstimateConfig, int heightEstimateConfig) {
                int width =measureDimension(dp2px(DEFAULT_SIZE,getContext()),widthEstimateConfig);
                int height =measureDimension(dp2px(DEFAULT_SIZE,getContext()),heightEstimateConfig);
                setEstimatedSize(width,height);
                return true;
            }
        });
        addDrawTask(this);

    }

    public void setIndicatorId(int  indicatorId){
        mIndicatorId = indicatorId;
        applyIndicator();
    }

    public void setIndicatorColor(int color){
        mIndicatorColor = color;
        mPaint.setColor(new Color(mIndicatorColor));
        this.invalidate();
    }



    private void applyIndicator(){
        switch (mIndicatorId){
            case SysProgress:
                mIndicatorController=new SysProgressIndicator();
                break;
            case BallPulse:
                mIndicatorController=new BallPulseIndicator();
                break;
            case BallGridPulse:
                mIndicatorController=new BallGridPulseIndicator();
                break;
            case BallClipRotate:
                mIndicatorController=new BallClipRotateIndicator();
                break;
            case BallClipRotatePulse:
                mIndicatorController=new BallClipRotatePulseIndicator();
                break;
            case SquareSpin:
                mIndicatorController=new SquareSpinIndicator();
                break;
            case BallClipRotateMultiple:
                mIndicatorController=new BallClipRotateMultipleIndicator();
                break;
            case BallPulseRise://待解决
                mIndicatorController=new BallPulseRiseIndicator();
                break;
            case BallRotate:
                mIndicatorController=new BallRotateIndicator();
                break;
            case CubeTransition://待解决
                mIndicatorController=new CubeTransitionIndicator();
                break;
            case BallZigZag://待解决
                mIndicatorController=new BallZigZagIndicator();
                break;
            case BallZigZagDeflect://待解决
                mIndicatorController=new BallZigZagDeflectIndicator();
                break;
            case BallTrianglePath://待解决
                mIndicatorController=new BallTrianglePathIndicator();
                break;
            case BallScale:
                mIndicatorController=new BallScaleIndicator();
                break;
            case LineScale:
                mIndicatorController=new LineScaleIndicator();
                break;
            case LineScaleParty:
                mIndicatorController=new LineScalePartyIndicator();
                break;
            case BallScaleMultiple:
                mIndicatorController=new BallScaleMultipleIndicator();
                break;
            case BallPulseSync:
                mIndicatorController=new BallPulseSyncIndicator();
                break;
            case BallBeat:
                mIndicatorController=new BallBeatIndicator();
                break;
            case LineScalePulseOut:
                mIndicatorController=new LineScalePulseOutIndicator();
                break;
            case LineScalePulseOutRapid:
                mIndicatorController=new LineScalePulseOutRapidIndicator();
                break;
            case BallScaleRipple:
                mIndicatorController=new BallScaleRippleIndicator();
                break;
            case BallScaleRippleMultiple:
                mIndicatorController=new BallScaleRippleMultipleIndicator();
                break;
            case BallSpinFadeLoader:
                mIndicatorController=new BallSpinFadeLoaderIndicator();
                break;
            case LineSpinFadeLoader:
                mIndicatorController=new LineSpinFadeLoaderIndicator();
                break;
            case TriangleSkewSpin:
                mIndicatorController=new TriangleSkewSpinIndicator();
                break;
            case Pacman://待解决
                mIndicatorController=new PacmanIndicator();
                break;
            case BallGridBeat:
                mIndicatorController=new BallGridBeatIndicator();
                break;
            case SemiCircleSpin:
                mIndicatorController=new SemiCircleSpinIndicator();
                break;
            default:
                break;
        }
        mIndicatorController.setTarget(this);
    }

    private int measureDimension(int defaultSize, int measureSpec){
        int result = defaultSize;
        int specMode = EstimateSpec.getMode(measureSpec);
        int specSize = EstimateSpec.getSize(measureSpec);
        if (specMode == EstimateSpec.PRECISE) {
            result = specSize;
        } else if (specMode == EstimateSpec.NOT_EXCEED) {
            result = Math.min(defaultSize, specSize);
        } else {
            result = defaultSize;
        }
        return result;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        drawIndicator(canvas);
    }

    @Override
    public void arrange(int left, int top, int width, int height) {
        super.arrange(left, top, width, height);
        if (!mHasAnimation){
            mHasAnimation=true;
            applyAnimation();
        }
    }

    @Override
    public void setVisibility(int visibility) {
        if(getVisibility() != visibility){
            super.setVisibility(visibility);
            if(mIndicatorController == null)
                return;
            if(visibility == HIDE || visibility == INVISIBLE){
                mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.END);
            }else {
                mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.START);
            }
        }
    }

    @Override
    public void onComponentBoundToWindow(Component component) {
        if(mIndicatorController == null)
            return;
        mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.START);
    }

    @Override
    public void onComponentUnboundFromWindow(Component component) {
        if(mIndicatorController == null)
            return;
        mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.CANCEL);
    }

    void drawIndicator(Canvas canvas){
        if(mIndicatorController == null)
            return;
        mIndicatorController.draw(canvas, mPaint);
    }


    public void applyAnimation(){
        if(mIndicatorController == null)
            return;
        mIndicatorController.initAnimation();
    }
    public void destroy(){
        mHasAnimation = true;
        if(mIndicatorController != null){
            mIndicatorController.destroy();
            mIndicatorController = null;
        }
        mPaint = null;
    }

    private final static float NORMAL_PIXEL_DENSITY = 160f;
    private static int dp2px(float dp, Context context) {
        float scale = context.getResourceManager().getDeviceCapability().screenDensity;
        return (int)(dp*scale/NORMAL_PIXEL_DENSITY + 0.5f);
    }
}
